package com.shinow.capacitor.plusins.decard.f11;

import android.app.Activity;
import android.util.Base64;

import com.decard.NDKMethod.BasicOper;
import com.decard.NDKMethod.SSCardDriver;
import com.decard.entitys.IDCard;
import com.getcapacitor.JSObject;
import com.getcapacitor.PluginCall;
import com.shinow.capacitor.plusins.decard.DecardRunTimeException;

import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class F11 {
	private static Boolean IdCardLoop = true;
	private static Long IdCardInterval = 1200L;
	private static Boolean SocialSecurityCardLoop = true;
	private static Long SocialSecurityCardInterval = 1200L;
	private static Boolean QRCodeLoop = true;
	private static Long QRCodeInterval = 1200L;


	public F11() {
		BasicOper.dc_setLanguageEnv(0);
	}

	public void dcOpen(Activity activity, JSObject parameter) throws DecardRunTimeException {
		String LineType = parameter.optString("Type", "AUSB"),
				Param = parameter.optString("Param", "/dev/ttyUSB0");
		int BaudRate = parameter.optInt("BaudRate", 115200),
				InitParameterResult = -1;

		int Result = BasicOper.dc_open(LineType, activity, Param, BaudRate);
		BasicOper.CreateAndroidContext(activity);

		if ("AUSB".equals(LineType)) {
			InitParameterResult = BasicOper.setInitParameter(2, null, 0);
		} else if ("COM".equals(LineType)) {
			InitParameterResult = BasicOper.setInitParameter(1, Param, BaudRate);
		}

		if (Result < 0 || InitParameterResult < 0) {
			throw new DecardRunTimeException("打开设备失败", Result);
		}
	}

	public void dcExit() throws DecardRunTimeException {
		int Result = BasicOper.dc_exit();

		if (Result != 0) {
			throw new DecardRunTimeException("关闭设备失败", Result);
		}
	}

	private static String bytesToBase64(byte[] Data) {
		return "data:image/jpeg;base64," + new String(Base64.encode(Data, Base64.DEFAULT));
	}

	private static JSObject iDCardToJSObject(IDCard idCard) {
		return new JSObject() {{
			this.put("type", idCard.getType());
			this.put("name", idCard.getName());
			this.put("sex", idCard.getSex());
			this.put("nation", idCard.getNation());
			this.put("birthday", idCard.getBirthday());
			this.put("address", idCard.getAddress());
			this.put("id", idCard.getId());
			this.put("office", idCard.getOffice());
			this.put("startTime", idCard.getStartTime());
			this.put("endTime", idCard.getEndTime());
			this.put("foreign_name", idCard.getForeign_name());
			this.put("foreign_sex", idCard.getForeign_sex());
			this.put("foreign_id", idCard.getForeign_id());
			this.put("foreign_citizenship", idCard.getForeign_citizenship());
			this.put("foreign_chinese_name", idCard.getForeign_chinese_name());
			this.put("foreign_expire_start_day", idCard.getForeign_expire_start_day());
			this.put("foreign_expire_end_day", idCard.getForeign_expire_end_day());
			this.put("foreign_birth_day", idCard.getForeign_birth_day());
			this.put("foreign_version_number", idCard.getForeign_version_number());
			this.put("foreign_department_code", idCard.getForeign_department_code());
			this.put("foreign_type_sign", idCard.getForeign_type_sign());
			this.put("foreign_reserved", idCard.getForeign_reserved());
			this.put("hongkong_macao_taiwan_nameStr", idCard.getHongkong_macao_taiwan_nameStr());
			this.put("hongkong_macao_taiwan_sexStr", idCard.getHongkong_macao_taiwan_sexStr());
			this.put("hongkong_macao_taiwan_birth_dayStr", idCard.getHongkong_macao_taiwan_birth_dayStr());
			this.put("hongkong_macao_taiwan_addressStr", idCard.getHongkong_macao_taiwan_addressStr());
			this.put("hongkong_macao_taiwan_idStr", idCard.getHongkong_macao_taiwan_idStr());
			this.put("hongkong_macao_taiwan_officeStr", idCard.getHongkong_macao_taiwan_officeStr());
			this.put("hongkong_macao_taiwan_expire_start_dayStr", idCard.getForeign_expire_start_day());
			this.put("hongkong_macao_taiwan_expire_end_dayStr", idCard.getForeign_expire_end_day());
			this.put("hongkong_macao_taiwan_traffic_permit_numStr", idCard.getHongkong_macao_taiwan_traffic_permit_numStr());
			this.put("hongkong_macao_taiwan_sign_issue_timeStr", idCard.getHongkong_macao_taiwan_sign_issue_timeStr());
			this.put("photoDataHexStr", idCard.getPhotoDataHexStr());
			this.put("photoData", idCard.getPhotoData());
			this.put("photoBase64", bytesToBase64(idCard.getPhotoData()));
			this.put("fingerprintData", idCard.getFingerprintData());
			this.put("extraData", idCard.getExtraData());
		}};
	}

	public JSObject readIdCard(JSObject parameter) throws DecardRunTimeException {
		IDCard idCard = BasicOper.dc_SamAReadCardInfo(parameter.optInt("Type", 3));

		if (idCard == null) {
			throw new DecardRunTimeException("无身份证");
		} else {
			return iDCardToJSObject(idCard);
		}
	}

	private static JSObject regExpMatchMergeData(JSObject Basics, String Data, String RegExp) {
		ArrayList<String> RegExpFields = new ArrayList<String>();
		Pattern RegExpPattern = Pattern.compile("(__[^\\|]*)");
		Pattern DataPattern = Pattern.compile(RegExp.replaceAll("__[^\\|]+", "([^|]*)").replaceAll("\\|", "\\\\|").replaceAll("\\$", "\\\\\\$"));
		Matcher RegExpMatcher = RegExpPattern.matcher(RegExp);
		Matcher DataMatcher = DataPattern.matcher(Data);

		while (RegExpMatcher.find()) {
			RegExpFields.add(RegExpMatcher.group().replace("__", ""));
		}

		if (DataMatcher.find() && DataMatcher.groupCount() == RegExpFields.size()) {
			for (int i = 0, length = DataMatcher.groupCount(); i < length; i++) {
				Basics.put(RegExpFields.get(i), DataMatcher.group(i + 1));
			}
		}

		return Basics;
	}

	public JSObject readSocialSecurityCard(JSObject parameter) throws DecardRunTimeException {
		try {
			byte[] SocialSecurityCardInfo = new byte[1024];
			long ReadState = SSCardDriver.iReadCardBas(parameter.optInt("CardType", 3), SocialSecurityCardInfo);

			if (ReadState != 0) {
				throw new DecardRunTimeException("读取社保卡失败");
			} else {
				SocialSecurityCard Result = new SocialSecurityCard(new String(SocialSecurityCardInfo, "GBK").trim());

				int CardCanonicalVersion = Integer.parseInt(Result.getString("CardCanonicalVersion", "1").substring(0, 1));
				String FileNameAndDataItem = "",
						DataRegExp = "";
				if (CardCanonicalVersion == 1) {
					FileNameAndDataItem = "SSSEEF05|02|04|$SSSEEF06|08|09|0A|0B|0C|0D|$";
					DataRegExp = "SSSEEF05|__CardClassFlag|__InitializationStructureNumber|$SSSEEF06|__Id|__Name|__SexFlag|__NationFlag|__BirthPlaceFlag|__DateBirth|$";
				} else if (CardCanonicalVersion == 2 || CardCanonicalVersion == 3) {
					FileNameAndDataItem = "SSSEEF05|02|04|$SSSEEF06|08|09|4E|0A|0B|0C|0D|$";
					DataRegExp = "SSSEEF05|__CardClassFlag|__InitializationStructureNumber|$SSSEEF06|__Id|__Name|__NameExpand|__SexFlag|__NationFlag|__BirthPlaceFlag|__DateBirth|$";
				}

				byte[] SocialSecurityCardDetailedInfo = new byte[20480];
				ReadState = SSCardDriver.iReadCard(parameter.optInt("CardType", 3), 1, Result.getString("CardIdentificationCode") + "|" + Result.getString("SocialSecurityCardNumber") + "|", FileNameAndDataItem, SocialSecurityCardDetailedInfo);
				if (ReadState == 0) {
					Result.regExpMatchMergeData(new String(SocialSecurityCardDetailedInfo, "UTF-8").trim(), DataRegExp);
				}

				return Result.conversionFlag();
			}
		} catch (UnsupportedEncodingException e) {
			throw new DecardRunTimeException("读取社保卡失败");
		}
	}

	private static void QRCodePowerOn() throws DecardRunTimeException {
		String[] ResultArr = BasicOper.dc_Scan2DBarcodeStart(0x00).split("\\|", -1);

		if (!ResultArr[0].equals("0000")) {
			throw new DecardRunTimeException(ResultArr[1], ResultArr[0]);
		}
	}

	private static void QRCodePowerOff() throws DecardRunTimeException {
		String[] ResultArr = BasicOper.dc_Scan2DBarcodeExit().split("\\|", -1);

		if (!ResultArr[0].equals("0000")) {
			throw new DecardRunTimeException(ResultArr[1], ResultArr[0]);
		}
	}

	private static String hexStringToUtf8(String Data) {
		byte[] Result = new byte[Data.length() / 2];

		for (int i = 0, length = Result.length; i < length; i++) {
			Result[i] = (byte) (0xFF & Integer.parseInt(Data.substring(i * 2, i * 2 + 2), 16));
		}

		return new String(Result, StandardCharsets.UTF_8);
	}

	public JSObject readQRCode(JSObject parameter) throws DecardRunTimeException {
		try {
			QRCodePowerOn();

			long StartTime = System.currentTimeMillis();
			long Timeout = parameter.optLong("Timeout", 12000L);
			while (System.currentTimeMillis() - StartTime < Timeout) {
				String[] ResultArr = BasicOper.dc_Scan2DBarcodeGetData().split("\\|", -1);
				if ("0000".equals(ResultArr[0])) {
					return new JSObject() {{
						this.put("QRCode", hexStringToUtf8(ResultArr[1]));
					}};
				}
			}

			throw new DecardRunTimeException("扫描超时");
		} finally {
			QRCodePowerOff();
		}
	}

	public void loopReadIdCard(PluginCall call) {
		call.setKeepAlive(true);
		IdCardInterval = call.getData().optLong("Interval", 1200L);
		IdCardLoop = call.getData().optBoolean("Loop", true);

		new Thread(new Runnable() {
			@Override
			public void run() {
				while (IdCardLoop) {
					try {
						JSObject Result = readIdCard(call.getData());
						call.resolve(Result);
					} catch (DecardRunTimeException e) {
						e.printStackTrace();
					}

					try {
						Thread.sleep(IdCardInterval);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}

				call.setKeepAlive(false);
			}
		}).start();
	}

	public void stopLoopReadIdCard() {
		IdCardLoop = false;
	}

	public void loopReadSocialSecurityCard(PluginCall call) {
		call.setKeepAlive(true);
		SocialSecurityCardInterval = call.getData().optLong("Interval", 1200L);
		SocialSecurityCardLoop = call.getData().optBoolean("Loop", true);

		new Thread(new Runnable() {
			@Override
			public void run() {
				while (SocialSecurityCardLoop) {
					try {
						JSObject Result = readSocialSecurityCard(call.getData());
						call.resolve(Result);
					} catch (DecardRunTimeException e) {
						e.printStackTrace();
					}

					try {
						Thread.sleep(SocialSecurityCardInterval);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}

				call.setKeepAlive(false);
			}
		}).start();
	}

	public void stopLoopReadSocialSecurityCard() {
		SocialSecurityCardLoop = false;
	}

	public void loopReadQRCode(PluginCall call) {
		call.setKeepAlive(true);
		QRCodeInterval = call.getData().optLong("Interval", 1200L);
		QRCodeLoop = call.getData().optBoolean("Loop", true);

		new Thread(new Runnable() {
			@Override
			public void run() {
				while (QRCodeLoop) {
					try {
						JSObject Result = readQRCode(call.getData());
						call.resolve(Result);
					} catch (DecardRunTimeException e) {
						e.printStackTrace();
					}

					try {
						Thread.sleep(QRCodeInterval);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}

				call.setKeepAlive(false);
			}
		}).start();
	}

	public void stopLoopReadQRCode() {
		QRCodeLoop = false;
	}
}
